#include "lcd_ctrl.h"
#include "graphic.h"
#include "axis.h"
#include "history.h"
#include "fsl_debug_console.h"
#include <tos_k.h>


static int elec_current = 0;
static k_mutex_t elec_mutex;
static int elec_freeze = 0;
static int force_refresh = 0;
static elec_mode_t elec_mode = ELEC_MODE_SECOND;

/* Background color. */
static const uint32_t bg_color = 0U;
static const uint32_t fg_color = 0x00FFFFFFU;
static const uint32_t data_color = 0x00FFFF00U;


static void on_axis_k_tick_t_2_scale_label(int x, char * label, uint32_t label_size)
{
	if (ELEC_MODE_SECOND == get_elec_mode())
	{
		k_tick_t_2_format_time_of_day(update_elec_time_begin(K_NULL) + x, label, label_size);
	} else
	{
		day_t d = k_tick_t_2_day_t(update_elec_time_begin(K_NULL));
		k_tick_t_2_format_date(day_t_2_k_tick_t(d + x), label, label_size);
	}
}

void lcd_ctrl_init(void)
{
	tos_mutex_create(&elec_mutex);
	axis_set_on_k_tick_t_2_x_scale_label(on_axis_k_tick_t_2_scale_label);
}

void lcd_ctrl_deinit(void)
{
	tos_mutex_destroy(&elec_mutex);
}

k_tick_t update_elec_time_begin_fl(k_tick_t * t)
{
	static k_tick_t elec_time_begin = 0;
	if (0 == elec_time_begin)
	{
		elec_time_begin = get_sys_time();
	}
	if (NULL != t)
	{
		k_tick_t ret = elec_time_begin;
		elec_time_begin = *t;
		return ret;
	}
	return elec_time_begin;
}

k_tick_t update_elec_time_begin(k_tick_t * t)
{
	tos_mutex_pend(&elec_mutex);
	k_tick_t rc = update_elec_time_begin_fl(t);
	tos_mutex_post(&elec_mutex);
    return rc;
}

k_tick_t update_elec_time_end_fl(k_tick_t * t)
{
	static k_tick_t elec_time_end = 0;
	if (0 == elec_time_end)
	{
		elec_time_end = update_elec_time_begin_fl(NULL) + CONF_X_AXIS_TIME_END_OFFSET * 1000;
	}
	if (NULL != t)
	{
		k_tick_t ret = elec_time_end;
		elec_time_end = *t;
		return ret;
	}
	return elec_time_end;
}

k_tick_t update_elec_time_end(k_tick_t * t)
{
	tos_mutex_pend(&elec_mutex);
	k_tick_t rc = update_elec_time_end_fl(t);
	tos_mutex_post(&elec_mutex);
    return rc;
}

void add_elec_value(int elec)
{
	tos_mutex_pend(&elec_mutex);
    elec_current += elec;
	tos_mutex_post(&elec_mutex);
}

static void on_get_each_elec_second(k_tick_t t, int value)
{
	axis_push_value_just(value);
}

static void on_get_each_elec_day(day_t t, int value)
{
	axis_push_value_just(value);
}

static int n_pushes = 0;

void lcd_ctrl_fill_framebuffer(uint32_t frameBuffer[APP_IMG_HEIGHT][APP_IMG_WIDTH])
{
	int value = 0;
	k_tick_t begin = 0;
    int do_push_value = 1;
	int freeze = 0;

    for (int i = 0; i < APP_IMG_HEIGHT; ++i)
    {
    	for (int j = 0; j < APP_IMG_WIDTH; ++j)
    	{
    		frameBuffer[i][j] = bg_color;
    	}
    }

	// Draw axis
	// {
	// 	tos_mutex_pend(&elec_mutex);
	// 	begin = update_elec_time_begin_fl(NULL);
	// 	// char begin_[24] = {0};
	// 	// k_tick_t_2_str(begin, begin_, sizeof(begin_));

	// 	freeze = elec_freeze;  // Put here to borrow the mutex

	// 	tos_mutex_post(&elec_mutex);
	// 	draw_axis(frameBuffer, begin, fg_color, bg_color);
	// }
	
	tos_mutex_pend(&elec_mutex);
	freeze = elec_freeze;
	tos_mutex_post(&elec_mutex);

	// Get the draw value
    if (!freeze)
	{
		// tos_mutex_pend(&elec_mutex);
		// value = elec_current;
		// elec_current = 0;
        // if (n_pushes < CONF_X_AXIS_SCALE_SECTION_N_POINTS * CONF_X_AXIS_N_SCALES)
        // {
        //     begin = update_elec_time_begin_fl(NULL);
        //     ++n_pushes;
        // } else
        // {
        //     begin = update_elec_time_begin_fl(NULL);
        //     begin += CONF_LCD_REFRESH_INTERVAL;
        //     update_elec_time_begin_fl(&begin);
        // }
		// tos_mutex_post(&elec_mutex);
	    // // Draw graphics
	    // axis_push_value(frameBuffer, value, begin, 1);
        axis_clear_values();
		// {
		// 	char time1[16] = {0};
		// 	k_tick_t_2_str(begin, time1, sizeof(time1));
		// 	PRINTF("Draw n_seconds: %d begin: %s\r\n", n_millis, time1);
		// }
		if (ELEC_MODE_SECOND == get_elec_mode())
		{
			k_tick_t cur = get_sys_time();
			k_tick_t begin;
			const k_tick_t mills = CONF_X_AXIS_N_SCALES * CONF_X_AXIS_SCALE_STEP;
			int n_millis;
			if (k_tick_t_2_day_seconds(cur) < mills / 1000)
			{
				n_millis = cur;
				begin = update_elec_time_begin(K_NULL);
			} else
			{
				n_millis = mills;
				cur -= mills;
				update_elec_time_begin(&cur);
				begin = cur;
			}
			axis_set_y_label(CONF_Y_AXIS_NAME_SECONDS);
        	history_get_second(begin, begin + n_millis - 1, on_get_each_elec_second);
		} else
		{
			k_tick_t begin = update_elec_time_begin(K_NULL);
			day_t day_begin = k_tick_t_2_day_t(begin);
			int n_days = CONF_X_AXIS_SCALE_SECTION_N_POINTS * CONF_X_AXIS_N_SCALES;
			day_t day_passed = k_tick_t_2_day_t(get_sys_time()) - day_begin + 1;
			if (day_passed < n_days)
			{
				n_days = day_passed;
			}
			axis_set_y_label(CONF_Y_AXIS_NAME_DAYS);
			history_get_day(day_begin, day_begin + n_days - 1, on_get_each_elec_day);
		}
        axis_redraw(frameBuffer);
	} else
    {
        axis_clear_values();
        tos_mutex_pend(&elec_mutex);
        k_tick_t begin = update_elec_time_begin_fl(K_NULL);
        tos_mutex_post(&elec_mutex);
		if (ELEC_MODE_SECOND == get_elec_mode())
		{
			axis_set_y_label(CONF_Y_AXIS_NAME_SECONDS);
        	history_get_second(begin, begin + CONF_X_AXIS_SCALE_STEP * CONF_X_AXIS_N_SCALES - 1,
				on_get_each_elec_second);
		} else
		{
			axis_set_y_label(CONF_Y_AXIS_NAME_DAYS);
			day_t day_begin = k_tick_t_2_day_t(begin);
			history_get_day(day_begin, day_begin + CONF_X_AXIS_SCALE_SECTION_N_POINTS * CONF_X_AXIS_N_SCALES - 1,
				on_get_each_elec_day);
		}
        axis_redraw(frameBuffer);
    }
}

int get_current_elec_value(void)
{
	tos_mutex_pend(&elec_mutex);
    int value = elec_current;
    tos_mutex_post(&elec_mutex);
    return value;
}

void freeze_lcd(int freeze)
{
	tos_mutex_pend(&elec_mutex);
    elec_freeze = freeze;
    tos_mutex_post(&elec_mutex);
}

void force_refresh_lcd(void)
{
	tos_mutex_pend(&elec_mutex);
	force_refresh = 1;
    tos_mutex_post(&elec_mutex);
}

int is_force_refresh_lcd(void)
{
	return force_refresh;
}

void clear_force_refresh_lcd(void)
{
	tos_mutex_pend(&elec_mutex);
	force_refresh = 0;
    tos_mutex_post(&elec_mutex);
}

void set_elec_mode(elec_mode_t mode)
{
	tos_mutex_pend(&elec_mutex);
	elec_mode = mode;
    tos_mutex_post(&elec_mutex);
}

elec_mode_t get_elec_mode(void)
{
	tos_mutex_pend(&elec_mutex);
	elec_mode_t mode = elec_mode;
    tos_mutex_post(&elec_mutex);
	return mode;
}
